package com.apes.fn.scm.prepare.service;


import com.apes.fn.fico.debitnote.model.BusinessDebitNote;
import com.apes.fn.scm.contract.FnContract;
import com.apes.fn.scm.contract.FnContractRepository;
import com.apes.fn.scm.prepare.model.Prepare;
import com.apes.fn.scm.prepare.model.PrepareDetail;
import com.apes.fn.scm.prepare.model.ToPrepare;
import com.apes.fn.scm.prepare.model.ToPrepareDetail;
import com.apes.fn.scm.prepare.repository.PrepareRepository;
import com.apes.fn.scm.prepare.repository.ToPrepareRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.ledger.service.LedgerService;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 缴款单
 */
@Service("prepareService")
public class PrepareService extends DomainService {
    @Autowired
    private PrepareRepository prepareRepository;

    @Autowired
    private ToPrepareRepository toPrepareRepository;

    @Autowired
    private LedgerService ledgerService;

    @Autowired
    private FnContractRepository fnContractRepository;
    /**
     * 创建
     * @param request
     * @return
     */
    public Prepare create(SimpleRequest request) {
        Prepare prepare = request.getO(Prepare.class);
        if (prepare.getToPrepareAmount() < prepare.getPrepareAmount()) throw new RuntimeException("缴款金额不能大于待缴款金额,请确认！");
        if (prepare.getPrepareAmount() <= 0) throw new RuntimeException("本次缴款金额不可小于等于0,请确认！");
        if (Objects.isNull(prepare.getPaymentReturn()) || prepare.getPaymentReturn().length() < 3)
            throw new RuntimeException("请上传缴款回执!");
        prepare.setCompany(SpringManager.getBean(PartyRoleRepository.class).findOne(prepare.getDept().getCompany().getId()));
        FnContract fnContract = fnContractRepository.findByPartnerAndState(prepare.getCompany().getId());
        if(fnContract != null){
            prepare.setPlatformCompany(fnContract.getCompany());
        }
//        prepare.setPrepareAccount(SpringManager.getBean(BankAccountRepository.class).getOne("000254"));//与花姐确定，因为门店就得麻烦，所以固定给000254
        Prepare prepareLedger = prepareRepository.saveAndFlush(prepare);
        return prepareLedger;
    }

    /**
     * 编辑
     * @param request
     * @return
     */
    public Prepare update(SimpleRequest request) {
        Prepare prepare = request.getO(Prepare.class);
        prepare.setCompany(SpringManager.getBean(PartyRoleRepository.class).findOne(prepare.getDept().getCompany().getId()));
        if (prepare.getToPrepareAmount() < prepare.getPrepareAmount()) throw new RuntimeException("缴款金额不能大于待缴款金额,请确认！");
        if (Objects.isNull(prepare.getPaymentReturn()) || prepare.getPaymentReturn().length() < 3)
            throw new RuntimeException("请上传缴款回执!");
        Prepare prepareLedger = prepareRepository.saveAndFlush(prepare);
        return prepareLedger;
    }

    /**
     * 写总账 账款：冻结项
     *
     * @param prepare
     */
    private void prepareLedger(Prepare prepare, String state) {
        List<FnContract> fnContracts = SpringManager.getBean(FnContractRepository.class).findAll(JpaDsl.toCriteriaByEq("partner.id", prepare.getCompany().getId(), "state", "approve"));
        FnContract fnContract = fnContracts.get(0);
        ledgerService.charge(fnContract.getCompany(), SpringManager.getBean(DeptRepository.class).findByPartyRoleAndDeptType(fnContract.getCompany().getId(), "000006"), fnContract.getPartner(), "IM_OWN", "AM_PURCHASE", prepare.getId(), "Prepare", new Date(), "current_unsettled", "delete".equals(state) ? prepare.getPrepareAmount() : prepare.getPrepareAmount() * -1);
    }

    public double findByaAndDeptId(SimpleRequest request) {
        double freezeAmount = toPrepareRepository.findByaAndDeptId(request.get("dept"), request.get("paymentType")).stream().mapToDouble(ToPrepare::getFreezeAmount).sum();
        return Arith.round(freezeAmount, 2);
    }

    /**
     * 审核并且分摊自动分摊待缴款
     *
     * @param request
     * @return
     */
    public Prepare approve(SimpleRequest request) {
        Prepare prepare = request.getO(Prepare.class);
        //出纳必须收款回执

        if (Objects.isNull(prepare.getCollectReturn()) || prepare.getCollectReturn().length() < 3)
            throw new RuntimeException("请上传收款回执!");

        Set<PrepareDetail> prepareDetailSet = new HashSet<>();
        List<Map> list = new ArrayList();
        double money = prepare.getPrepareAmount();
        //通过部门查询出当前部门所有的待缴款金额
        List<ToPrepare> toPrepares = toPrepareRepository.findByaAndDeptId(prepare.getDept().getId(), prepare.getPaymentType().getId());
        double round = Arith.round(toPrepares.stream().mapToDouble(ToPrepare::getFreezeAmount).sum(), 2);
        if (Arith.round(prepare.getPrepareAmount(), 2) > round)
            throw new RuntimeException("本次缴款金额小于待缴款总额" + round + "，请确认！");
        toPrepares.forEach(toPrepare -> {
            if (prepare.getPrepareAmount() <= 0) return;
            PrepareDetail prepareDetail = new PrepareDetail();
            //回写待缴款
            if (prepare.getPrepareAmount() >= toPrepare.getFreezeAmount()) {
                prepare.setPrepareAmount(prepare.getPrepareAmount() - toPrepare.getFreezeAmount());
                prepareDetail.setTheAmount(toPrepare.getFreezeAmount());
                toPrepare.setRecoveryAmount(toPrepare.getRecoveryAmount() + toPrepare.getFreezeAmount());
                toPrepare.setFreezeAmount(toPrepare.getFreezeAmount() - toPrepare.getFreezeAmount());
            } else {
                toPrepare.setRecoveryAmount(toPrepare.getRecoveryAmount() + prepare.getPrepareAmount());
                toPrepare.setFreezeAmount(toPrepare.getFreezeAmount() - prepare.getPrepareAmount());
                prepareDetail.setTheAmount(prepare.getPrepareAmount());
                prepare.setPrepareAmount(0);
            }
            toPrepareRepository.saveAndFlush(toPrepare);
            //缴款明细
            prepareDetail.setRecoveryAmount(toPrepare.getRecoveryAmount());
            prepareDetail.setPaymentTime(toPrepare.getCollectMoneyDate());
            prepareDetail.setToPrepare(toPrepare);
            prepareDetail.setFreezeAmount(toPrepare.getFreezeAmount());
            prepareDetailSet.add(prepareDetail);
            if (toPrepare.getToPrepareDetails().size() > 0) {
                list.add(detail(toPrepare.getToPrepareDetails(), prepareDetail.getTheAmount()));//回写定损数组
            }
        });

        if ("private_homes".equals(prepare.getPaymentType().getCode()) && list.size() > 0) {
            invoke("fn.lossQuotation.prepare", list);
        }
        prepare.setPrepareDetailSet(prepareDetailSet);
        prepare.setState("approve");
        prepare.setApproveUid(getPerson(request));
        prepare.setApproveDate(new Date());
        prepare.setPrepareAmount(money);
        prepareLedger(prepare, prepare.getState());
        return prepareRepository.saveAndFlush(prepare);
    }

    public Map detail(Set<ToPrepareDetail> toPrepareDetails, double amount) {
        Map map = new HashMap();
        toPrepareDetails.forEach(toPrepareDetail -> {
            map.put("amount", amount);
            map.put("lossReceivedItemId", toPrepareDetail.getRecord());
            map.put("lossQuotationId", toPrepareDetail.getSource());
        });
        return map;
    }

    /**
     * 删除
     *
     * @param request
     * @return
     */
    public String delete(SimpleRequest request) {
        Prepare prepare = request.getO(Prepare.class);
        prepare.setState("delete");
        prepareRepository.saveAndFlush(prepare);
        return "删除成功";
    }

    /**
     * 终止预支单
     *
     * @param request
     * @return
     */
    public Prepare repeal(SimpleRequest request) {
        Prepare prepare = request.getO(Prepare.class);
        List<Map> list = new ArrayList();
        //回写待缴款金额的缴款金额
        if (Objects.nonNull(prepare.getAdvanceUid())) throw new RuntimeException("该缴款单已有预支单，不允许终止！");
        prepare.getPrepareDetailSet().forEach(prepareDetail -> {
            ToPrepare toPrepare = toPrepareRepository.findOne(prepareDetail.getToPrepare().getId());
            if (toPrepare.getToPrepareDetails().size() > 0) {
                list.add(detail(toPrepare.getToPrepareDetails(), prepareDetail.getTheAmount() * -1));//回写定损数组
            }
            toPrepare.setRecoveryAmount(prepareDetail.getToPrepare().getRecoveryAmount() - prepareDetail.getTheAmount());
            toPrepare.setFreezeAmount(prepareDetail.getToPrepare().getFreezeAmount() + prepareDetail.getTheAmount());
            toPrepareRepository.saveAndFlush(toPrepare);
        });

        //扣除已经扣除的定损报价单
        if ("private_homes".equals(prepare.getPaymentType().getCode()) && list.size() > 0) {
            invoke("fn.lossQuotation.prepare", list);
        }
        prepare.setState("repeal");
        Prepare prepareLedger = prepareRepository.saveAndFlush(prepare);
        prepareLedger(prepareLedger, "delete");
        return prepareLedger;
    }

    public Prepare findOne(SimpleRequest request) {
        String id = request.get("PREPARE");
        return prepareRepository.findOne(id);
    }

    public Prepare businessDebitNote(SimpleRequest request) {
        Prepare prepare = request.getO(Prepare.class);
        if ("98".equals(prepare.getType().getId())) throw new RuntimeException("该收款方式不可生成预支单！");
        if (Objects.isNull(prepare.getRefundAccount())) throw new RuntimeException("门店回款账户为空，不可操作'生成预支'功能！");

        prepare.setAdvanceUid(getPerson(request));//生成预支人
        prepare.setAdvanceDate(new Date());//生成预支日期
        BusinessDebitNote businessDebitNote = invoke("fn.businessDebitNote.prepare", MapUtil.mapped(prepare));//生成预支单
        prepare.setRemarks(businessDebitNote.getId());
        String note = StringUtils.isEmpty(prepare.getNote())?"": prepare.getNote()+",";
        prepare.setNote(note+ "已自动生成预支单，" + businessDebitNote.getId() + "。");
        return prepareRepository.saveAndFlush(prepare);
    }
}
